//////////////////////////////////////////////
// Shader.h
//
//////////////////////////////////////////////

/// Defines / Macros -------------------------

#pragma once

/// Foward decl ------------------------------

namespace nkGraphics
{
	class Buffer ;
	class ConstantBuffer ;
	class Program ;
	class Sampler ;
	class ShaderInstanceMemorySlot ;
	class ShaderPassMemorySlot ;
	class ShaderResource ;
	class System ;
}

/// Includes ---------------------------------

// nkGraphics
#include "ShaderResourceDesc.h"

#include "../Dll/DllDefines.h"

#include "../Resources/Resource.h"

#include "../Utils/DxDefinesWrapper.h"

// nkExport
#include <NilkinsExport/Exportable/Exportable.h>

// nkMemory
#include <NilkinsMemory/Pointers/UniquePtr.h>

// Standards
#include <vector>

/// Class ------------------------------------
	
namespace nkGraphics
{
	class DLL_GRAPHICS_EXPORT Shader : public Resource, public nkExport::Exportable
	{		
		public :
		
			// Destructor
			virtual ~Shader () ;

			// Getters
			unsigned int getId () const ;
			bool isUsableScene () const ;
			bool isUsablePostProcess () const ;
			bool isUsableCompute () const ;
			bool isUsableGeometry () const ;
			bool isUsableRaytracing () const ;
			Program* getProgram () const ;
			unsigned int getMaxInstancePerBuffer () const ;
			bool getIsBuiltInShader () const ;
			bool getDirtyInstanceData () const ;

			// Setters
			virtual void setProgram (Program* prog) ;
			void setId (unsigned int id) ;
			virtual void setMaxInstancePerBuffer (unsigned int value) ;
			void setIsBuiltInShader (bool value) ;
			void setDirtyInstanceData (bool value) ;

			// Init
			virtual bool load () override ;
			virtual void unload () override ;
			void reset () ;

			// Constant buffers
			ConstantBuffer* addConstantBuffer (unsigned int registerSlot, unsigned int space = 0) ;
			ConstantBuffer* getConstantBuffer (unsigned int slot, unsigned int space = 0) const ;
			void changeConstantBufferSlot (unsigned int fromSlot, unsigned int toSlot, unsigned int space = 0) ;
			void changeConstantBufferSpace (unsigned int fromSpace, unsigned int toSpace, unsigned int slot) ;
			void deleteConstantBuffer (unsigned int slot, unsigned int space = 0) ;
			const ConstantBufferResourceDesc* getConstantBufferPerIndex (unsigned int index) const ;

			// Textures
			void addTexture (ShaderResource* texOrUav, unsigned int registerSlot, unsigned int space = 0) ;
			ShaderResource* getTexture (unsigned int slot, unsigned int space = 0) const ;
			void setTexture (ShaderResource* texOrUav, unsigned int slot, unsigned int space = 0) ;
			void changeTextureSlot (unsigned int fromSlot, unsigned int toSlot, unsigned int space = 0) ;
			void changeTextureSpace (unsigned int fromSpace, unsigned int toSpace, unsigned int slot) ;
			void forgetTexture (unsigned int slot, unsigned int space = 0) ;
			const ShaderResourceDesc* getTexturePerIndex (unsigned int index) const ;

			// Samplers
			void addSampler (Sampler* sampler, unsigned int registerSlot, unsigned int space = 0) ;
			Sampler* getSampler (unsigned int slot, unsigned int space = 0) const ;
			void setSampler (Sampler* sampler, unsigned int slot, unsigned int space = 0) ;
			void changeSamplerSlot (unsigned int fromSlot, unsigned int toSlot, unsigned int space = 0) ;
			void changeSamplerSpace (unsigned int fromSpace, unsigned int toSpace, unsigned int slot = 0) ;
			void forgetSampler (unsigned int slot, unsigned int space = 0) ;
			const SamplerResourceDesc* getSamplerPerIndex (unsigned int index) const ;

			// UAV
			void addUavBuffer (Buffer* buffer, unsigned int registerSlot, unsigned int space = 0) ;
			Buffer* getUavBuffer (unsigned int slot, unsigned int space = 0) const ;
			void setUavBuffer (Buffer* buffer, unsigned int slot, unsigned int space = 0) ;
			void changeUavBufferSlot (unsigned int fromSlot, unsigned int toSlot, unsigned int space = 0) ;
			void changeUavBufferSpace (unsigned int fromSpace, unsigned int toSpace, unsigned int slot = 0) ;
			void forgetUavBuffer (unsigned int slot, unsigned int space = 0) ;
			const UavResourceDesc* getUavBufferPerIndex (unsigned int index) const ;

			// Instance data
			virtual ShaderInstanceMemorySlot* addInstanceMemorySlot () ;
			virtual ShaderInstanceMemorySlot* getInstanceMemorySlot (unsigned int index) ;
			virtual ShaderInstanceMemorySlot* getInstanceMemorySlotReadOnly (unsigned int index) const ;
			virtual void changeInstanceMemorySlotOrder (unsigned int fromIndex, unsigned int toIndex) ;
			virtual void deleteInstanceMemorySlot (unsigned int index) ;
			bool hasInstanceSlotSemanticName (nkMemory::StringView name) const ;

			// Import / Export
			virtual void exportClassToTree (nkExport::Node* rootNode) override ;
			virtual void importClassFromTree (nkExport::Node* rootNode) override ;

		public :

			// Statics
			static nkMemory::UniquePtr<Shader> create (System* system = nullptr) ;

		protected :

			// Fonctions
			// Constructor
			Shader (System* system) noexcept ;

			// Allocations
			virtual ConstantBuffer* allocateConstantBuffer () = 0 ;
			virtual ShaderInstanceMemorySlot* allocateInstanceMemorySlot () = 0 ;

		protected :

			// Attributs
			// Associated program
			Program* _program ;

			// Read data that can be provided
			std::vector<ConstantBufferResourceDesc> _constantBuffers ;
			std::vector<ShaderResourceDesc> _textureSlots ;
			std::vector<SamplerResourceDesc> _samplerSlots ;

			// UAV list
			std::vector<UavResourceDesc> _uavSlots ;

			// Instance slots
			std::vector<ShaderInstanceMemorySlot*> _instanceSlots ;

			// Identifier
			unsigned int _id ;

			// Counter
			unsigned int _maxInstancePerBuffer ;

			// Flags
			bool _isBuiltInShader ;
			bool _dirtyInstanceData ;
	} ;
}